{
 "metadata": {
  "language": "lua",
  "name": "",
  "signature": "sha256:b10c4d04cf3575ac928ba5b76d2bfba46b9be7d2f476f56313ab03e63d4b8b45"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "## Tensor\n",
      "The ___Tensor___ class is probably the most important class in ___Torch___. Almost every package depends on this class. It is __the__ class for handling numeric data. \n",
      "\n",
      "As with pretty much anything in ___Torch___, tensors are serializable and deserializable. What that means is that you can convert a tensor to a string (and save it as a file to disk), and load it back.\n",
      "\n",
      "### Multi-dimensional matrix\n",
      "A ___Tensor___ is a potentially multi-dimensional matrix. The number of dimensions is unlimited that can be created using ___LongStorage___ with more dimensions.\n",
      "\n",
      "Example: "
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "--- creation of a 4D-tensor 4x5x6x2\n",
      "z = torch.Tensor(4,5,6,2)\n",
      "--- for more dimensions, (here a 6D tensor) one can do:\n",
      "s = torch.LongStorage(6)\n",
      "s[1] = 4; s[2] = 5; s[3] = 6; s[4] = 2; s[5] = 7; s[6] = 3;\n",
      "x = torch.Tensor(s)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 1
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The number of dimensions of a Tensor can be queried by ___nDimension()___ or ___dim()___. Size of the i-th dimension is returned by ___size(i)___. A ___LongStorage___ containing all the dimensions can be returned by ___size()___."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "print(x:nDimension())"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 2,
       "text": [
        "6\t\n"
       ]
      }
     ],
     "prompt_number": 2
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "print(x:size())"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 3,
       "text": [
        "\n",
        " 4\n",
        " 5\n",
        " 6\n",
        " 2\n",
        " 7\n",
        " 3\n",
        "[torch.LongStorage of size 6]\n",
        "\n"
       ]
      }
     ],
     "prompt_number": 3
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "### Internal data representation\n",
      "The actual data of a ___Tensor___ is contained into a ___Storage___. It can be accessed using ___storage()___. While the memory of a ___Tensor___ has to be contained in this unique ___Storage___, it might not be __contiguous__: the first position used in the ___Storage___ is given by ___storageOffset()___ (starting at 1). And the jump needed to go from one element to another element in the i-th dimension is given by ___stride(i)___. In other words, given a 3D tensor"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "x = torch.Tensor(7,7,7)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 4
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "accessing the element (3,4,5) can be done by"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "x[3][4][5]"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 5,
       "text": [
        "0\t\n"
       ]
      }
     ],
     "prompt_number": 5
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "or equivalently under the hood (but slowly!)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "x:storage()[x:storageOffset()\n",
      "           +(3-1)*x:stride(1)\n",
      "           +(4-1)*x:stride(2)\n",
      "           +(5-1)*x:stride(3)\n",
      "           ]"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 6,
       "text": [
        "0\t\n"
       ]
      }
     ],
     "prompt_number": 6
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "One could say that a ___Tensor___ is a particular way of viewing a ___Storage___: a ___Storage___ only represents a chunk of memory, while the ___Tensor___ interprets this chunk of memory as having dimensions:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "x = torch.Tensor(4,5)\n",
      "s = x:storage()\n",
      "for i=1,s:size() do -- fill up the Storage\n",
      "    s[i] = i\n",
      "end\n",
      "print(x)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 7,
       "text": [
        "  1   2   3   4   5\n",
        "  6   7   8   9  10\n",
        " 11  12  13  14  15\n",
        " 16  17  18  19  20\n",
        "[torch.DoubleTensor of dimension 4x5]\n",
        "\n"
       ]
      }
     ],
     "prompt_number": 7
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Note also that in Torch elements in the same row [elements along the last dimension] are contiguous in memory for a Tensor:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "x = torch.Tensor(4,5)\n",
      "i = 0\n",
      "x:apply(function()\n",
      "     i = i + 1\n",
      "     return i\n",
      "    end)\n",
      "print(x)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 8,
       "text": [
        "  1   2   3   4   5\n",
        "  6   7   8   9  10\n",
        " 11  12  13  14  15\n",
        " 16  17  18  19  20\n",
        "[torch.DoubleTensor of dimension 4x5]\n",
        "\n"
       ]
      }
     ],
     "prompt_number": 8
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "x:stride() -- element in the last dimension are contiguous!"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 9
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "This is exactly like in __C__ (and not __Fortran__)."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "### Tensors of different types\n",
      "Actually, several types of Tensor exist:\n",
      "* ByteTensor -- contains unsigned chars\n",
      "* CharTensor -- contains signed chars\n",
      "* ShortTensor -- contains shorts\n",
      "* IntTensor -- contains ints\n",
      "* FloatTensor -- contains floats\n",
      "* DoubleTensor -- contains doubles\n",
      "\n",
      "Most numeric operations are implemented only for ___FloatTensor___ and ___DoubleTensor___. Other ___Tensor___ types are useful if you want to save memory space."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "### Default Tensor type\n",
      "For convenience, an alias ___torch.Tensor___ is provided, which allows the user to write type-independent scripts, which can then ran after choosing the desired ___Tensor___ type with a call like"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "torch.setdefaulttensortype('torch.FloatTensor')"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 10,
       "text": [
        "\n"
       ]
      }
     ],
     "prompt_number": 10
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "See ___torch.setdefaulttensortype___ for more details. By default, the alias \"points\" to ___torch.DoubleTensor___."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 11,
       "text": [
        "\n"
       ]
      }
     ],
     "prompt_number": 11
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [],
     "language": "python",
     "metadata": {},
     "outputs": []
    }
   ],
   "metadata": {}
  }
 ]
}